﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Microsoft.EntityFrameworkCore;
using pandx.Mulan.Authorization.Users;
using pandx.Mulan.Extensions;
using pandx.Mulan.Flow.FlowInstances.Dto;
using pandx.Mulan.Flows;
using Abp.Runtime.Session;
using pandx.Mulan.Authorization;
using pandx.Mulan.Dto;
using pandx.Mulan.Flow.FlowInstances.Exporting;
using pandx.Mulan.Forms;
using pandx.Mulan.Notifications;

namespace pandx.Mulan.Flow.FlowInstances
{
    public class FlowInstanceAppService : MulanAppServiceBase, IFlowInstanceAppService
    {
        private readonly IRepository<FlowInstance, long> _flowInstanceRepository;
        private readonly IRepository<FlowScheme, long> _flowSchemeRepository;
        private readonly IRepository<UserRole, long> _userRoleRepository;
        private readonly IRepository<FlowTransitionHistory, long> _flowTransitionHistoryRepository;
        private readonly IRepository<FlowOperationHistory, long> _flowOperationHistoryRepository;
        private readonly IRepository<FlowCopy, long> _flowCopyRepository;
        private readonly IRepository<FormScheme, long> _formSchemRepository;
        private readonly IAppNotifier _appNotifier;
        private readonly IFlowInstanceListExcelExporter _flowInstanceListExcelExporter;

        public FlowInstanceAppService(IRepository<FlowInstance, long> flowInstanceRepository,
            IRepository<FlowScheme, long> flowSchemeRepository,
            IRepository<UserRole, long> userRoleRepository,
            IRepository<FlowTransitionHistory, long> flowTransitionHistoryRepository,
            IRepository<FlowOperationHistory, long> flowOperationHistoryRepository,
            IRepository<FlowCopy, long> flowCopyRepository,
            IRepository<FormScheme, long> formSchemRepository,
            IAppNotifier appNotifier,
            IFlowInstanceListExcelExporter flowInstanceListExcelExporter)
        {
            _flowInstanceRepository = flowInstanceRepository;
            _flowSchemeRepository = flowSchemeRepository;
            _userRoleRepository = userRoleRepository;
            _flowTransitionHistoryRepository = flowTransitionHistoryRepository;
            _flowOperationHistoryRepository = flowOperationHistoryRepository;
            _flowCopyRepository = flowCopyRepository;
            _formSchemRepository = formSchemRepository;
            _appNotifier = appNotifier;
            _flowInstanceListExcelExporter = flowInstanceListExcelExporter;
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Browse)]
        public async Task<PagedResultDto<FlowInstanceListDto>> ObtainFlowInstances(ObtainFlowInstancesInput input)
        {
            var query = await CreateFlowInstanceAndUsersQuery(input);

            var instancesCount = await query.CountAsync();
            var instances = await query.Distinct().OrderBy(input.Sorting).PageBy(input).ToListAsync();
            var dtos = instances.Select(item =>
            {
                var dto = ObjectMapper.Map<FlowInstanceListDto>(item.Instance);
                dto.CreationUserName = item.User.UserName;
                dto.CreationFullName = item.User.Name;
                dto.Flag = item.Flag;
                dto.HistoryCount =
                    _flowTransitionHistoryRepository.Count(h =>
                        h.InstanceId == item.Instance.Id && h.CreatorUserId != item.Instance.CreatorUserId);
                return dto;
            }).ToList();
            return new PagedResultDto<FlowInstanceListDto>(instancesCount, dtos);
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Export)]
        public async Task<FileDto> ObtainFlowInstancesToExcel(ObtainFlowInstancesInput input)
        {
            var instances =await  (await CreateFlowInstanceAndUsersQuery(input)).AsNoTracking().OrderBy(input.Sorting)
                .ToListAsync();
            var dtos = instances.Select(item =>
            {
                var dto = ObjectMapper.Map<FlowInstanceListDto>(item.Instance);
                dto.CreationUserName = item.User.UserName;
                dto.CreationFullName = item.User.Name;
                dto.Flag = item.Flag;
                dto.HistoryCount =
                    _flowTransitionHistoryRepository.Count(h =>
                        h.InstanceId == item.Instance.Id && h.CreatorUserId != item.Instance.CreatorUserId);
                return dto;
            }).ToList();
            return _flowInstanceListExcelExporter.ExportToExcel(dtos);
        }

        public async Task CreateOrUpdateFlowInstance(CreateOrUpdateFlowInstanceInput input)
        {
            if (input.FlowInstance.Id.HasValue)
            {
                await UpdateFlowInstanceAsync(input);
            }
            else
            {
                await CreateFlowInstanceAsync(input);
            }
        }
       
        private async Task UpdateFlowInstanceAsync(CreateOrUpdateFlowInstanceInput input)
        {
            if (input.FlowInstance.Id.HasValue)
            {
                var instance = await _flowInstanceRepository.GetAsync(input.FlowInstance.Id.Value);
                ObjectMapper.Map(input.FlowInstance, instance);
            }
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Launch)]
        protected  virtual  async Task CreateFlowInstanceAsync(CreateOrUpdateFlowInstanceInput input)
        {
            CheckRuntimeAllot(input);

            //以下是流程模板的相关处理
            var scheme = await _flowSchemeRepository.GetAsync(input.FlowInstance.FlowSchemeId);
            if (scheme == null)
            {
                throw new UserFriendlyException("该流程模板已经不存在，请重新设计");
            }

            input.FlowInstance.FlowSchemeContent = scheme.SchemeContent;

            //以下是表单模板的相关处理
            var form = await _formSchemRepository.GetAsync(scheme.FormId);
            if (form == null)
            {
                throw new UserFriendlyException("该流程模板对应的表单模板已经不存在，请重新设计");
            }

            input.FlowInstance.FormSchemeId = form.Id;
            input.FlowInstance.FormSchemeName = form.SchemeName;
            input.FlowInstance.FormType = (FormType)form.FormType;
            input.FlowInstance.FormSchemeContent = form.SchemeContent;

            var instance = ObjectMapper.Map<FlowInstance>(input.FlowInstance);
            var runtime = new FlowRuntime(instance);

            //根据运行实例改变当前节点
            // flowInstance.ActivityNodeId = runtime.NextNodeId;
            // flowInstance.ActivityNodeType = runtime.NextNodeType;
            // flowInstance.ActivityNodeName = runtime.NextNode.Name;
            //
            // flowInstance.PrevNodeId = runtime.CurrentNodeId;
            // flowInstance.NextUserIds = runtime.NextNodeType != FlowNode.End ? await GetNextUserIds(runtime, input) : "";
            // flowInstance.State = runtime.NextNodeType == FlowNode.End
            //     ? FlowInstanceState.Finished
            //     : FlowInstanceState.Running;
            instance.ActivityNodeId = runtime.NextNode.Id;
            instance.ActivityNodeName = runtime.NextNode.Name;
            instance.ActivityNodeType = runtime.NextNode.Type;
            instance.PrevNodeId = runtime.CurrentNode.Id;
            var userIds = "";
            if (runtime.NextNode.Type != FlowNode.End)
            {
                userIds = await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input.FlowInstance));
                
            }
            instance.NextUserIds = userIds;
            
            // instance.NextUserIds = runtime.NextNode.Type != FlowNode.End
            //     ? await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input.FlowInstance))
            //     : "";
            instance.State = runtime.NextNode.Type == FlowNode.End
                ? FlowInstanceState.Finished
                : FlowInstanceState.Running;
            instance.TenantId = AbpSession.TenantId;
            instance.FlowSchemeContent = new
            {
                Name = runtime.Name,
                NodeList = runtime.Nodes.Select(n => n.Value),
                LineList = runtime.Lines,
            }.ObjectToJson();

            var instanceId = await _flowInstanceRepository.InsertAndGetIdAsync(instance);
            runtime.InstanceId = instanceId;

            //此处去发送通知
            List<UserIdentifier> users = new List<UserIdentifier>();
            if (userIds != "ALL" && userIds!="")
            {
                foreach (var userId in userIds.Split(','))
                {
                    users.Add(new UserIdentifier(AbpSession.TenantId, Convert.ToInt64(userId)));
                }

                await _appNotifier.NeedToVerify(users.ToArray(), instanceId, instance.Name,  (await UserManager.GetUserAsync(AbpSession.ToUserIdentifier())).Name);
            }
            //TODO 此处的代码需要考虑一下
            //抄送开始
            // if (runtime.NextNode.Info.Copy)
            // {
            //     List<UserIdentifier> users = new List<UserIdentifier>();
            //     foreach (var userId in runtime.NextNode.Info.CopyUsers)
            //     {
            //         if (await _flowCopyRepository.GetAll()
            //                 .SingleOrDefaultAsync(c => c.InstanceId == instanceId && c.UserId == userId) == null)
            //         {
            //             users.Add(new UserIdentifier(AbpSession.TenantId,userId));
            //             await _flowCopyRepository.InsertAsync(new FlowCopy
            //             {
            //                 InstanceId = instance.Id,
            //                 UserId = userId
            //             });
            //         }
            //     }
            //
            //     await _appNotifier.HaveToCopy(users.ToArray(), instance.Id);
            // }

            // if (input.FlowInstance.Copy)
            // {
            //     List<UserIdentifier> users = new List<UserIdentifier>();
            //     foreach (var userId in input.FlowInstance.CopyUsers)
            //     {
            //         if (await _flowCopyRepository.GetAll()
            //                 .SingleOrDefaultAsync(c => c.InstanceId == instanceId && c.UserId == userId) == null)
            //         {
            //             users.Add(new UserIdentifier(AbpSession.TenantId, userId));
            //             await _flowCopyRepository.InsertAsync(new FlowCopy
            //             {
            //                 InstanceId = instance.Id,
            //                 UserId = userId
            //             });
            //         }
            //     }
            //
            //     await _appNotifier.HaveToCopy(users.ToArray(), instance.Id, instance.Name,
            //         (await UserManager.GetUserAsync(AbpSession.ToUserIdentifier())).Name);
            // }
            //抄送结束

            //流程操作记录
            await _flowOperationHistoryRepository.InsertAsync(new FlowOperationHistory
            {
                TenantId = AbpSession.TenantId,
                InstanceId = instance.Id,
                Operation = "新创建",
                NodeName = runtime.CurrentNode.Name,
                NodeType = runtime.CurrentNode.Type,
                SignState = SignState.Null
            });
            await AddTransitionHistory(runtime, false);
            await CurrentUnitOfWork.SaveChangesAsync();
        }

        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Display)]
        public async Task<GetFlowInstanceForVerifyOutput> GetFlowInstanceForVerify(EntityDto<long> input)
        {
            var query = from i in _flowInstanceRepository.GetAll()
                join u in UserManager.Users on i.CreatorUserId equals u.Id
                where i.Id == input.Id
                select new
                {
                    Instance = i,
                    User = u
                };
            var result = await query.FirstOrDefaultAsync();
            if (result != null)
            {
                var dto = ObjectMapper.Map<FlowInstanceListDto>(result.Instance);
                dto.CreationFullName = result.User.Name;
                dto.CreationUserName = result.User.UserName;
                dto.HistoryCount = _flowTransitionHistoryRepository.Count(h =>
                    h.InstanceId == result.Instance.Id && h.CreatorUserId != result.Instance.CreatorUserId);
                return new GetFlowInstanceForVerifyOutput
                {
                    FlowInstance = dto
                };
            }
            else
            {
                return null;
            }
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Restart)]
        public async Task<GetFlowInstanceForEditOutput> GetFlowInstanceForEdit(EntityDto<long> input)
        {
            var instance = await _flowInstanceRepository.GetAsync(input.Id);
            return new GetFlowInstanceForEditOutput
            {
                FlowInstance = ObjectMapper.Map<FlowInstanceEditDto>(instance)
            };
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Delete)]
        public async Task DeleteFlowInstance(EntityDto<long> input)
        {
            var instance = await _flowInstanceRepository.GetAsync(input.Id);
            if (instance.State == FlowInstanceState.Draft ||
                (await GetCurrentUserAsync()).UserName == AbpUserBase.AdminUserName)
            {
                await _flowInstanceRepository.DeleteAsync(input.Id);
            }
            else
            {
                throw new UserFriendlyException("当前状态下无法完成删除操作");
            }
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Display)]
        public async Task<ListResultDto<FlowOperationHistoryListDto>> GetFlowOperationHistories(EntityDto<long> input)
        {
            var query = from history in _flowOperationHistoryRepository.GetAll()
                join user in UserManager.Users on history.CreatorUserId equals user.Id
                join instance in _flowInstanceRepository.GetAll() on history.InstanceId equals instance.Id
                where history.InstanceId == input.Id
                select new
                {
                    History = history,
                    User = user,
                    Instance = instance
                };
            var histories = await query.OrderBy(q => q.History.CreationTime).ToListAsync();
            var dtos = histories.Select(item =>
            {
                var dto = ObjectMapper.Map<FlowOperationHistoryListDto>(item.History);
                dto.InstanceCode = item.Instance.Code;
                dto.InstanceName = item.Instance.Name;
                dto.CreationFullName = item.User.Name;
                dto.CreationUserName = item.User.UserName;
                return dto;
            }).ToList();
            return new ListResultDto<FlowOperationHistoryListDto>(dtos);
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Working)]
        //暂存
        public async Task WorkingFlowInstance(CreateOrUpdateFlowInstanceInput input)
        {
            // CheckRuntimeAllot(input);
            //以下是流程模板的相关处理
            var scheme = await _flowSchemeRepository.GetAsync(input.FlowInstance.FlowSchemeId);
            if (scheme == null)
            {
                throw new UserFriendlyException("该流程模板已经不存在，请重新设计");
            }

            input.FlowInstance.FlowSchemeContent = scheme.SchemeContent;

            //以下是表单模板的相关处理
            var form = await _formSchemRepository.GetAsync(scheme.FormId);
            if (form == null)
            {
                throw new UserFriendlyException("该流程模板对应的表单模板已经不存在，请重新设计");
            }

            input.FlowInstance.FormSchemeId = form.Id;
            input.FlowInstance.FormSchemeName = form.SchemeName;
            input.FlowInstance.FormType = (FormType)form.FormType;
            input.FlowInstance.FormSchemeContent = form.SchemeContent;

            var instance = ObjectMapper.Map<FlowInstance>(input.FlowInstance);
            var runtime = new FlowRuntime(instance);

            //根据运行实例改变当前节点
            // flowInstance.ActivityNodeId = runtime.NextNodeId;
            // flowInstance.ActivityNodeType = runtime.NextNodeType;
            // flowInstance.ActivityNodeName = runtime.NextNode.Name;
            //
            // flowInstance.PrevNodeId = runtime.CurrentNodeId;
            // flowInstance.NextUserIds = runtime.NextNodeType != FlowNode.End ? await GetNextUserIds(runtime, input) : "";
            // flowInstance.State = runtime.NextNodeType == FlowNode.End
            //     ? FlowInstanceState.Finished
            //     : FlowInstanceState.Running;
            instance.ActivityNodeId = runtime.StartNode.Id;
            instance.ActivityNodeName = runtime.StartNode.Name;
            instance.ActivityNodeType = runtime.StartNode.Type;
            instance.PrevNodeId = "";
            // instance.NextUserIds = runtime.NextNode.Type != FlowNode.End
            //     ? await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input.FlowInstance))
            //     : "";
            // instance.State = runtime.NextNode.Type == FlowNode.End
            //     ? FlowInstanceState.Finished
            //     : FlowInstanceState.Running;
            instance.NextUserIds = "";
            instance.State = FlowInstanceState.Draft;
            instance.TenantId = AbpSession.TenantId;
            instance.FlowSchemeContent = new
            {
                Name = runtime.Name,
                NodeList = runtime.Nodes.Select(n => n.Value),
                LineList = runtime.Lines,
            }.ObjectToJson();

            var instanceId = await _flowInstanceRepository.InsertAndGetIdAsync(instance);
            runtime.InstanceId = instanceId;

            //流程操作记录
            await _flowOperationHistoryRepository.InsertAsync(new FlowOperationHistory
            {
                TenantId = AbpSession.TenantId,
                InstanceId = instance.Id,
                Operation = "被暂存",
                NodeName = runtime.StartNode.Name,
                NodeType = runtime.StartNode.Type,
                SignState = SignState.Null
            });
            // await AddTransitionHistory(runtime, false);
            await CurrentUnitOfWork.SaveChangesAsync();
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Restart)]
        //重启
        public async Task RestartFlowInstance(CreateOrUpdateFlowInstanceInput input)
        {
            FlowInstance instance = new FlowInstance();

            if (input.FlowInstance.Id.HasValue)
            {
                instance = await _flowInstanceRepository.GetAsync(input.FlowInstance.Id.Value);
            }

            if (instance.State == FlowInstanceState.Draft || instance.State == FlowInstanceState.Rejected)
            {
                ObjectMapper.Map(input.FlowInstance, instance);
                FlowRuntime runtime = new FlowRuntime(instance);

                if (string.IsNullOrWhiteSpace(instance.NextUserIds))
                {
                    //从草稿启动
                    CheckRuntimeAllot(input);
                    instance.ActivityNodeId = runtime.NextNode.Id;
                    instance.ActivityNodeName = runtime.NextNode.Name;
                    instance.ActivityNodeType = runtime.NextNode.Type;
                    instance.PrevNodeId = runtime.CurrentNode.Id;
                    var userIds = "";
                    if (runtime.NextNode.Type != FlowNode.End)
                    {
                        userIds = await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input.FlowInstance));
                    }

                    // instance.NextUserIds = runtime.NextNode.Type != FlowNode.End
                    //     ? await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input.FlowInstance))
                    //     : "";
                    //此处发送通知
                    List<UserIdentifier> users = new List<UserIdentifier>();
                    if (userIds != "ALL" && userIds!="")
                    {
                        foreach (var userId in userIds.Split(','))
                        {
                            users.Add(new UserIdentifier(AbpSession.TenantId, Convert.ToInt64(userId)));
                        }

                        await _appNotifier.NeedToVerify(users.ToArray(), instance.Id, instance.Name,  (await UserManager.GetUserAsync(new UserIdentifier(AbpSession.TenantId,
                            instance.CreatorUserId.Value))).Name);
                    }
                }
                else
                {
                    instance.ActivityNodeId = runtime.PrevNode.Id;
                    instance.ActivityNodeName = runtime.PrevNode.Name;
                    instance.ActivityNodeType = runtime.PrevNode.Type;
                    instance.PrevNodeId = runtime.CurrentNode.Id;
                    // instance.NextUserIds=runtime.NextNode.Type!=FlowNode.End   
                    //     ? await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input))
                    //     : "";
                }

                instance.State = runtime.NextNode.Type == FlowNode.End
                    ? FlowInstanceState.Finished
                    : FlowInstanceState.Running;
                instance.FlowSchemeContent = new
                {
                    Name = runtime.Name,
                    NodeList = runtime.Nodes.Select(n => n.Value),
                    LineList = runtime.Lines,
                }.ObjectToJson();

                //流程操作记录
                await _flowOperationHistoryRepository.InsertAsync(new FlowOperationHistory
                {
                    TenantId = AbpSession.TenantId,
                    InstanceId = instance.Id,
                    Operation = "重启动",
                    NodeName = runtime.CurrentNode.Name,
                    NodeType = runtime.CurrentNode.Type,
                    SignState = SignState.Null
                });
                await AddTransitionHistory(runtime, false);
                await CurrentUnitOfWork.SaveChangesAsync();
            }
            else
            {
                throw new UserFriendlyException("当前状态下无法完成重启操作");
            }
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Recall)]
        //召回
        public async Task RecallFlowInstance(EntityDto<long> input)
        {
            var instance = await _flowInstanceRepository.GetAsync(input.Id);
            if (instance.State == FlowInstanceState.Running &&
                (await _flowTransitionHistoryRepository.CountAsync(f =>
                    f.InstanceId == instance.Id && f.CreatorUserId != instance.CreatorUserId)) == 0)
            {
                //可以召回
                var scheme = await _flowSchemeRepository.GetAsync(instance.FlowSchemeId);
                if (scheme == null)
                {
                    throw new UserFriendlyException("该流程模板已经不存在，请重新设计");
                }

                instance.FlowSchemeContent = scheme.SchemeContent;

                //以下是表单的相关处理
                // var form =await  _formSchemRepository.GetAsync(scheme.FormId);
                // if (form == null)
                // {
                //     throw new UserFriendlyException("该流程模板对应的表单模板已经不存在，请重新设计");
                // }
                //
                // input.FlowInstance.FormSchemeId = form.Id;
                // input.FlowInstance.FormSchemeName = form.SchemeName;
                // input.FlowInstance.FormType = (FormType)form.FormType;
                // input.FlowInstance.FormSchemeContent = form.SchemeContent;

                // var instance = ObjectMapper.Map<FlowInstance>(input.FlowInstance);
                var runtime = new FlowRuntime(instance);

                //根据运行实例改变当前节点
                // flowInstance.ActivityNodeId = runtime.NextNodeId;
                // flowInstance.ActivityNodeType = runtime.NextNodeType;
                // flowInstance.ActivityNodeName = runtime.NextNode.Name;
                //
                // flowInstance.PrevNodeId = runtime.CurrentNodeId;
                // flowInstance.NextUserIds = runtime.NextNodeType != FlowNode.End ? await GetNextUserIds(runtime, input) : "";
                // flowInstance.State = runtime.NextNodeType == FlowNode.End
                //     ? FlowInstanceState.Finished
                //     : FlowInstanceState.Running;
                instance.ActivityNodeId = runtime.StartNode.Id;
                instance.ActivityNodeName = runtime.StartNode.Name;
                instance.ActivityNodeType = runtime.StartNode.Type;
                instance.PrevNodeId = runtime.CurrentNode.Id;
                // instance.NextUserIds = runtime.NextNode.Type != FlowNode.End
                //     ? await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input.FlowInstance))
                //     : "";
                // instance.State = runtime.NextNode.Type == FlowNode.End
                //     ? FlowInstanceState.Finished
                //     : FlowInstanceState.Running;
                instance.NextUserIds = "";
                instance.State = FlowInstanceState.Draft;
                instance.TenantId = AbpSession.TenantId;
                instance.FlowSchemeContent = new
                {
                    Name = runtime.Name,
                    NodeList = runtime.Nodes.Select(n => n.Value),
                    LineList = runtime.Lines,
                }.ObjectToJson();

                // var instanceId = await _flowInstanceRepository.InsertAndGetIdAsync(instance);

                runtime.InstanceId = instance.Id;

                //流程操作记录
                await _flowOperationHistoryRepository.InsertAsync(new FlowOperationHistory
                {
                    TenantId = AbpSession.TenantId,
                    InstanceId = instance.Id,
                    Operation = "被召回",
                    NodeName = runtime.StartNode.Name,
                    NodeType = runtime.StartNode.Type,
                    SignState = SignState.Null
                });
                // await AddTransitionHistory(runtime, false);
                await CurrentUnitOfWork.SaveChangesAsync();
            }
            else
            {
                throw new UserFriendlyException("当前状态下无法完成召回操作");
            }
        }
        [AbpAuthorize(AppPermissions.Pages_FlowInstances_Verify)]
        //审核节点
        public async Task VerifyNode(VerifyNodeInput input)
        {
            var user = await GetCurrentUserAsync();
            var instanceId = input.InstanceId;

            var instance = await _flowInstanceRepository.GetAsync(instanceId);
            //判断用户是否有权限处理该节点
            if (instance.NextUserIds != "ALL" && !instance.NextUserIds.Contains(user.Id.ToString()))
            {
                throw new UserFriendlyException("用户 " + user.Name + " 没有审核该节点的权限");
            }

            //TODO 这里有问题，暂时搁置
            // var q = from i in _flowInstanceRepository.GetAll().Where(s=>s.Id==instanceId)
            //     join t in _flowTransitionHistoryRepository.GetAll() on instance.Id equals t
            //         .InstanceId
            //     join u in UserManager.Users on instance.CreatorUserId equals u.Id
            //     where t.CreatorUserId == user.Id && t.FromNodeType != FlowNode.Start &&
            //           i.ActivityNodeId == t.FromNodeId
            //     select new {i, t, u};
            // if (await q.CountAsync() > 0)
            // {
            //     throw new UserFriendlyException("用户 " + user.Name + " 已处理过该节点，请勿重复处理");
            // }
            if (instance.State == FlowInstanceState.Running)
            {
                FlowRuntime runtime = new FlowRuntime(instance);

                runtime.CurrentNode.Info.Signs.Add(new Sign
                {
                    UserId = user.Id,
                    UserName = user.Name,
                    Description = input.Description,
                    SignState = input.SignState,
                    SignTime = DateTime.Now
                });
                // instance.SchemeContent = new
                // {
                //     Name = runtime.Name,
                //     NodeList = runtime.Nodes.Select(n => n.Value),
                //     LineList = runtime.Lines,
                // }.ObjectToJson();

                var join = CurrentIsJoin(runtime);

                //会签
                if (join)
                {
                    if (runtime.CurrentNode.Info.JoinType == "ALL" || input.JoinType.ToUpper() == "ALL")
                    {
                        //会签，如果NextUserIds多于1个用户，直接更新NextUserIds
                        if (instance.NextUserIds.Split(',').Length > 1)
                        {
                            await MultipleUsers(instance, runtime, input, user);
                            await AddTransitionHistory(runtime, true);
                        }
                        //会签，如果NextUserIds仅余1个用户，流转到下一个节点
                        else
                        {
                            await SingleUser(instance, runtime, input, user);
                            await AddTransitionHistory(runtime, false);
                        }
                    }
                    //或签
                    else
                    {
                        await SingleUser(instance, runtime, input, user);
                        await AddTransitionHistory(runtime, false);
                    }
                }
                //普通审核
                else
                {
                    await SingleUser(instance, runtime, input, user);
                    await AddTransitionHistory(runtime, false);
                }

                instance.FlowSchemeContent = new
                {
                    Name = runtime.Name,
                    NodeList = runtime.Nodes.Select(n => n.Value),
                    LineList = runtime.Lines,
                }.ObjectToJson();

                await _flowInstanceRepository.UpdateAsync(instance);

                //流程操作记录
                Dictionary<SignState, string> operations = new Dictionary<SignState, string>
                {
                    { SignState.Yes, "已同意" },
                    { SignState.No, "被拒绝" },
                    { SignState.Reject, "被驳回" }
                };
                await _flowOperationHistoryRepository.InsertAsync(new FlowOperationHistory
                {
                    TenantId = AbpSession.TenantId,
                    InstanceId = instance.Id,
                    NodeName = runtime.CurrentNode.Name,
                    NodeType = runtime.CurrentNode.Type,
                    Operation = operations[input.SignState],
                    SignState = input.SignState,
                    Description = input.Description,
                });

                if (instance.ActivityNodeId == runtime.EndNode.Id && instance.State == FlowInstanceState.Finished)
                {
                    await _flowOperationHistoryRepository.InsertAsync(new FlowOperationHistory
                    {
                        TenantId = AbpSession.TenantId,
                        InstanceId = instance.Id,
                        NodeName = runtime.EndNode.Name,
                        NodeType = runtime.EndNode.Type,
                        Operation = "已结束",
                        SignState = SignState.Null,
                    });
                }


                //TODO 抄送
                if (runtime.CurrentNode.Info.Copy)
                {
                    List<UserIdentifier> users = new List<UserIdentifier>();
                    foreach (var userId in runtime.CurrentNode.Info.CopyUsers)
                    {
                        if (await _flowCopyRepository.GetAll()
                                .SingleOrDefaultAsync(c => c.InstanceId == instance.Id && c.UserId == userId) == null)
                        {
                            users.Add(new UserIdentifier(AbpSession.TenantId, userId));
                            await _flowCopyRepository.InsertAsync(new FlowCopy
                            {
                                InstanceId = instance.Id,
                                UserId = userId
                            });
                        }
                    }

                    await _appNotifier.HaveToCopy(users.ToArray(), instance.Id, instance.Name,
                        (await UserManager.GetUserAsync(AbpSession.ToUserIdentifier())).Name);
                }

                if (input.Copy)
                {
                    List<UserIdentifier> users = new List<UserIdentifier>();
                    foreach (var userId in input.CopyUsers)
                    {
                        if (await _flowCopyRepository.GetAll()
                                .SingleOrDefaultAsync(c => c.InstanceId == instance.Id && c.UserId == userId) == null)
                        {
                            users.Add(new UserIdentifier(AbpSession.TenantId, userId));
                            await _flowCopyRepository.InsertAsync(new FlowCopy
                            {
                                InstanceId = instance.Id,
                                UserId = userId
                            });
                        }
                    }

                    await _appNotifier.HaveToCopy(users.ToArray(), instance.Id, instance.Name,
                        (await UserManager.GetUserAsync(AbpSession.ToUserIdentifier())).Name);
                }

                await CurrentUnitOfWork.SaveChangesAsync();
            }
            else
            {
                throw new UserFriendlyException("当前状态下无法完成审核操作");
            }
        }
        [AbpAuthorize]
        public async Task<long> GetBacklogCount()
        {
            var user = await GetCurrentUserAsync();
            var query = from instance in _flowInstanceRepository.GetAll()
                join u in UserManager.Users on instance.CreatorUserId equals u.Id
                where (instance.NextUserIds == "" || instance.NextUserIds == null ||
                       instance.NextUserIds.Contains(user.Id.ToString())) &&
                      instance.State == FlowInstanceState.Running
                select new FlowInstanceAndUser
                {
                    Instance = instance,
                    User = u,
                    Flag = "backlog"
                };
            return query.Count();
        }

        //节点有一个用户审核或多个用户中的最后一个用户审核
        private async Task SingleUser(FlowInstance instance, FlowRuntime runtime, VerifyNodeInput input, User user)
        {
            switch (input.SignState)
            {
                case SignState.Yes:
                    instance.PrevNodeId = instance.ActivityNodeId;
                    instance.ActivityNodeId = runtime.NextNode.Id;
                    instance.ActivityNodeName = runtime.NextNode.Name;
                    instance.ActivityNodeType = runtime.NextNode.Type;
                    instance.State = runtime.NextNode.Type == FlowNode.End
                        ? FlowInstanceState.Finished
                        : FlowInstanceState.Running;
                    //更新用户
                    var userIds = "";
                    if (runtime.NextNode.Type != FlowNode.End)
                    {
                        userIds = await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input));
                    }

                    // instance.NextUserIds = runtime.NextNode.Type == FlowNode.End
                    //     ? ""
                    //     : await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input));
                    //此处发送通知
                    List<UserIdentifier> users = new List<UserIdentifier>();
                    if (userIds != "ALL" && userIds!="")
                    {
                        foreach (var userId in userIds.Split(','))
                        {
                            users.Add(new UserIdentifier(AbpSession.TenantId, Convert.ToInt64(userId)));
                        }

                        await _appNotifier.NeedToVerify(users.ToArray(), instance.Id, instance.Name,  (await UserManager.GetUserAsync(new UserIdentifier(AbpSession.TenantId,
                            instance.CreatorUserId.Value))).Name);
                    }
                    break;
                case SignState.No:
                    instance.State = FlowInstanceState.Deny;
                    instance.PrevNodeId = runtime.CurrentNode.Id;
                    instance.ActivityNodeId = runtime.EndNode.Id;
                    instance.ActivityNodeName = runtime.EndNode.Name;
                    instance.ActivityNodeType = runtime.EndNode.Type;
                    //更新用户
                    // instance.NextUserIds = (runtime.NextNode.Type == FlowNode.End
                    //     ? ""
                    //     : await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input)));
                    instance.NextUserIds = "";
                    break;
                case SignState.Reject:

                    instance.State = FlowInstanceState.Rejected;
                    instance.PrevNodeId = runtime.CurrentNode.Id;
                    instance.ActivityNodeId = runtime.StartNode.Id;
                    instance.ActivityNodeName = runtime.StartNode.Name;
                    instance.ActivityNodeType = runtime.StartNode.Type;
                    //更新用户
                    // instance.NextUserIds = (runtime.NextNode.Type == FlowNode.End
                    //     ? ""
                    //     : await GetNextUserIds(runtime, ObjectMapper.Map<AllotInput>(input)));
                    // instance.NextUserIds = "";

                    // var draftInstance = instance.Clone();
                    // draftInstance.Id = 0;
                    // draftInstance.RejectNodeId = runtime.CurrentNode.Id;
                    //
                    // draftInstance.ActivityNodeId = runtime.StartNode.Id;
                    // draftInstance.ActivityNodeName = runtime.StartNode.Name;
                    // draftInstance.ActivityNodeType = runtime.StartNode.Type;
                    // draftInstance.NextUserIds = user.Id.ToString();
                    // draftInstance.State = FlowInstanceState.Draft;
                    //移除草稿的审核信息
                    // runtime.CurrentNode.Info.Signs.Clear();
                    // draftInstance.SchemeContent = new
                    // {
                    //     Name = runtime.Name,
                    //     NodeList = runtime.Nodes.Select(n => n.Value),
                    //     LineList = runtime.Lines,
                    // }.ObjectToJson();
                    // await _flowInstanceRepository.InsertAsync(draftInstance);
                    break;
                default:
                    throw new UserFriendlyException("参数错误，请检查");
            }

            await _appNotifier.HaveToVerify(new UserIdentifier(instance.TenantId, instance.CreatorUserId.Value),
                instance.Id, instance.Name, (await UserManager.GetUserAsync(AbpSession.ToUserIdentifier())).Name);
        }

        //节点有多个用户审核
        private async Task MultipleUsers(FlowInstance instance, FlowRuntime runtime, VerifyNodeInput input, User user)
        {
            switch (input.SignState)
            {
                case SignState.Yes:
                    //会签，更新用户
                    var nextUserIdsList = instance.NextUserIds.Split(',').ToList();
                    nextUserIdsList.Remove(user.Id.ToString());
                    instance.NextUserIds = string.Join(',', nextUserIdsList);
                    instance.State = FlowInstanceState.Running;
                    break;
                case SignState.No:
                    instance.NextUserIds = "";

                    instance.State = FlowInstanceState.Deny;
                    instance.PrevNodeId = runtime.CurrentNode.Id;
                    instance.ActivityNodeId = runtime.EndNode.Id;
                    instance.ActivityNodeName = runtime.EndNode.Name;
                    instance.ActivityNodeType = runtime.EndNode.Type;
                    break;
                case SignState.Reject:
                    // var tempNextUserIds = instance.NextUserIds;
                    // instan1`ce.NextUserIds = "";

                    instance.State = FlowInstanceState.Rejected;
                    instance.PrevNodeId = runtime.CurrentNode.Id;
                    instance.ActivityNodeId = runtime.StartNode.Id;
                    instance.ActivityNodeName = runtime.StartNode.Name;
                    instance.ActivityNodeType = runtime.StartNode.Type;
                    //直接驳回到发起人，复制当前实例1份放到草稿箱，将流程的下一步执行者设置为驳回的用户

                    // var draftInstance = instance.Clone();
                    // draftInstance.Id = 0;
                    // draftInstance.RejectNodeId = runtime.CurrentNode.Id;
                    //
                    // draftInstance.ActivityNodeId = runtime.StartNode.Id;
                    // draftInstance.ActivityNodeName = runtime.StartNode.Name;
                    // draftInstance.ActivityNodeType = runtime.StartNode.Type;
                    // draftInstance.NextUserIds = tempNextUserIds;
                    // draftInstance.State = FlowInstanceState.Draft;
                    //移除草稿的审核信息
                    // runtime.CurrentNode.Info.Signs.Clear();
                    // draftInstance.SchemeContent = new
                    // {
                    //     Name = runtime.Name,
                    //     NodeList = runtime.Nodes.Select(n => n.Value),
                    //     LineList = runtime.Lines,
                    // }.ObjectToJson();
                    // await _flowInstanceRepository.InsertAsync(draftInstance);
                    break;
                default:
                    throw new UserFriendlyException("参数错误，请检查");
            }

            await _appNotifier.HaveToVerify(new UserIdentifier(instance.TenantId, instance.CreatorUserId.Value),
                instance.Id, instance.Name, (await UserManager.GetUserAsync(AbpSession.ToUserIdentifier())).Name);
        }

        private void CheckRuntimeAllot(CreateOrUpdateFlowInstanceInput input)
        {
            if ((input.FlowInstance.Allot == Info.RunningUser && input.FlowInstance.Users.Length == 0) ||
                (input.FlowInstance.Allot == Info.RunningRole && input.FlowInstance.Roles.Length == 0))
            {
                throw new UserFriendlyException("下个节点需要选择执行用户或执行角色");
            }
        }

        private async Task<string> GetNextUserIds(FlowRuntime runtime, AllotInput input)
        {
            var userIds = "";
            if (runtime.NextNode.Id == null)
            {
                throw new UserFriendlyException("无法找到下一个节点");
            }

            //节点包含多个用户，进入会签
            if (runtime.NextNode.Type == FlowNode.Task &&
                !runtime.NextNode.Info.JoinType.IsNullOrWhiteSpace())
            {
                if (!runtime.NextNode.Info.UserText.IsNullOrWhiteSpace())
                {
                    userIds = string.Join(',', runtime.NextNode.Info.Users);
                }

                if (!runtime.NextNode.Info.RoleText.IsNullOrWhiteSpace())
                {
                    var roleIds = runtime.NextNode.Info.Roles;
                    // if (runtime.NextNode.Info.SameUnit)
                    // {
                    //处理限定在同一单位的情况
                    //TODO
                    // }
                    // else
                    // {
                    var query = from user in UserManager.Users
                        join ur in _userRoleRepository.GetAll() on user.Id equals ur.UserId
                        join role in RoleManager.Roles on ur.RoleId equals role.Id
                        where roleIds.Contains(role.Id)
                        select user.Id;

                    userIds = string.Join(',', await query.ToListAsync());
                    // }
                }
            }
            else if (runtime.NextNode.Info.Allot == Info.RunningUser)
            {
                if (Info.RunningUser != input.Allot)
                {
                    throw new UserFriendlyException("参数错误，请检查");
                }

                userIds = string.Join(',', input.Users);
                runtime.NextNode.Info.Users = input.Users;
                runtime.NextNode.Info.UserText = input.UserText;
                runtime.NextNode.Info.JoinType = input.JoinType;
                runtime.NextNode.Info.Copy = input.Copy;
                runtime.NextNode.Info.CopyUsers = input.CopyUsers;
                runtime.NextNode.Info.CopyUserText = input.CopyUserText;
                // runtime.NextNode.Info.SameUnit = input.SameUnit;
            }
            else if (runtime.NextNode.Info.Allot == Info.RunningRole)
            {
                if (Info.RunningRole != input.Allot)
                {
                    throw new UserFriendlyException("参数错误，请检查");
                }

                // if (input.SameUnit)
                // {
                //     //TODO 处理限定在同一单位情况
                // }

                var roleIds = input.Roles;
                var query = from user in UserManager.Users
                    join ur in _userRoleRepository.GetAll() on user.Id equals ur.UserId
                    join role in RoleManager.Roles on ur.RoleId equals role.Id
                    where roleIds.Contains(role.Id)
                    select user.Id;
                userIds = string.Join(',', await query.ToListAsync());

                runtime.NextNode.Info.Roles = input.Roles;
                runtime.NextNode.Info.RoleText = input.RoleText;
                runtime.NextNode.Info.JoinType = input.JoinType;
                runtime.NextNode.Info.Copy = input.Copy;
                runtime.NextNode.Info.CopyUsers = input.CopyUsers;
                runtime.NextNode.Info.CopyUserText = input.CopyUserText;
                // runtime.NextNode.Info.SameUnit = input.SameUnit;
            }
            else if (runtime.NextNode.Info.Allot == Info.Everyone)
            {
                userIds = "ALL";
            }
            else
            {
                userIds = string.Join(',', runtime.NextNode.Info.Users);
            }

            if (userIds.IsNullOrWhiteSpace())
            {
                throw new UserFriendlyException("无法找到节点的处理用户，请检查流程");
            }

            return userIds;
        }


        private bool CurrentIsJoin(FlowRuntime runtime)
        {
            var c1 = runtime.CurrentNode.Type == FlowNode.Task &&
                     !runtime.CurrentNode.Info.JoinType.IsNullOrWhiteSpace();
            var c2 = runtime.CurrentNode.Info.Allot == Info.RunningUser && runtime.CurrentNode.Info.Users.Length > 1;
            var c3 = runtime.CurrentNode.Info.Allot == Info.RunningRole;
            return c1 || c2 || c3;
        }

        private async Task AddTransitionHistory(FlowRuntime runtime, bool isMultiple)
        {
            var user = await GetCurrentUserAsync();
            if (isMultiple)
            {
                await _flowTransitionHistoryRepository.InsertAsync(new FlowTransitionHistory
                {
                    TenantId = AbpSession.TenantId,
                    InstanceId = runtime.InstanceId,
                    FromNodeId = runtime.CurrentNode.Id,
                    FromNodeType = runtime.CurrentNode.Type,
                    FromNodeName = runtime.CurrentNode.Name,
                    ToNodeId = runtime.CurrentNode.Id,
                    ToNodeType = runtime.CurrentNode.Type,
                    ToNodeName = runtime.CurrentNode.Name,
                    State = runtime.NextNode.Type == FlowNode.End
                        ? FlowInstanceState.Finished
                        : FlowInstanceState.Running
                });
            }
            else
            {
                await _flowTransitionHistoryRepository.InsertAsync(new FlowTransitionHistory
                {
                    TenantId = AbpSession.TenantId,
                    InstanceId = runtime.InstanceId,
                    FromNodeId = runtime.CurrentNode.Id,
                    FromNodeType = runtime.CurrentNode.Type,
                    FromNodeName = runtime.CurrentNode.Name,
                    ToNodeId = runtime.NextNode.Id,
                    ToNodeType = runtime.NextNode.Type,
                    ToNodeName = runtime.NextNode.Name,
                    State = runtime.NextNode.Type == FlowNode.End
                        ? FlowInstanceState.Finished
                        : FlowInstanceState.Running
                });
            }
            // await CurrentUnitOfWork.SaveChangesAsync();
        }

        private async Task<IQueryable<FlowInstanceAndUser>> CreateFlowInstanceAndUsersQuery(ObtainFlowInstancesInput input)
        {
            var user = await GetCurrentUserAsync();
            IQueryable<FlowInstanceAndUser> query = null;
            //抄送给我的流程
            if (input.Type.ToUpper() == "COPY")
            {
                query = from instance in _flowInstanceRepository.GetAll()
                    join u in UserManager.Users on instance.CreatorUserId equals u.Id
                    join copy in _flowCopyRepository.GetAll() on instance.Id equals copy.InstanceId
                    join cu in UserManager.Users on copy.UserId equals cu.Id
                    where cu.Id == user.Id
                    select new FlowInstanceAndUser
                    {
                        Instance = instance,
                        User = u,
                        Flag = "copy"
                    };
            }

            //待处理的流程
            if (input.Type.ToUpper() == "BACKLOG")
            {
                query = from instance in _flowInstanceRepository.GetAll()
                    join u in UserManager.Users on instance.CreatorUserId equals u.Id
                    where (instance.NextUserIds == "" || instance.NextUserIds == null ||
                           instance.NextUserIds.Contains(user.Id.ToString())) &&
                          instance.State == FlowInstanceState.Running
                    select new FlowInstanceAndUser
                    {
                        Instance = instance,
                        User = u,
                        Flag = "backlog"
                    };

                // var instanceCount = await query.CountAsync();
                // var instances = await query.OrderBy(input.Sorting).PageBy(input).ToListAsync();
                // return new PagedResultDto<FlowInstanceListDto>(instanceCount,
                //     ObjectMapper.Map<List<FlowInstanceListDto>>(instances));
            }

            //已处理的流程
            if (input.Type.ToUpper() == "FINISHED")
            {
                query = from instance in _flowInstanceRepository.GetAll()
                    join transition in _flowTransitionHistoryRepository.GetAll() on instance.Id equals transition
                        .InstanceId
                    join u in UserManager.Users on instance.CreatorUserId equals u.Id
                    where transition.CreatorUserId == user.Id && transition.FromNodeType != FlowNode.Start
                    select new FlowInstanceAndUser
                    {
                        Instance = instance,
                        User = u,
                        Flag = "finished"
                    };
            }

            //发起的流程
            if (input.Type.ToUpper() == "LAUNCH")
            {
                query = from instance in _flowInstanceRepository.GetAll()
                    join u in UserManager.Users on instance.CreatorUserId equals u.Id
                    where instance.CreatorUserId == user.Id && instance.State != FlowInstanceState.Draft
                    select new FlowInstanceAndUser
                    {
                        Instance = instance,
                        User = u,
                        Flag = "launch",
                    };
            }

            //草稿箱
            if (input.Type.ToUpper() == "DRAFT")
            {
                query = from instance in _flowInstanceRepository.GetAll()
                    join u in UserManager.Users on instance.CreatorUserId equals u.Id
                    where instance.CreatorUserId == user.Id && instance.State == FlowInstanceState.Draft
                    select new FlowInstanceAndUser
                    {
                        Instance = instance,
                        User = u,
                        Flag = "draft"
                    };
            }

            //搜索
            query = query.Where(x =>
                    x.Instance.CreationTime >= input.StartTime && x.Instance.CreationTime <= input.EndTime)
                .WhereIf(input.State.HasValue, x => x.Instance.State == input.State)
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(),
                    x => x.Instance.Name.Contains(input.Filter) || x.Instance.Description.Contains(input.Filter));

            return query;
        }
    }
}